package com.retrofit.retrofitutil

import android.content.Context
import android.text.TextUtils
import okhttp3.Cache
import okhttp3.Interceptor
import okhttp3.OkHttpClient
import retrofit2.CallAdapter
import retrofit2.Converter
import retrofit2.Retrofit
import java.io.File
import java.util.*
import java.util.concurrent.TimeUnit

/**
 * 构建retrofit
 */
class RetrofitBuilder private constructor() {
    private var baseUrl: String = ""
    private var handleCookie: Boolean = true
    private var extraParamMap = TreeMap<String, String>()
    private val extraHeaderMap = TreeMap<String, String>()
    private val extraInterceptorList = arrayListOf<Interceptor>()
    private var maxCacheSize = 1024_000_000L
    private var connectTimeoutMs: Long = 10_000
    private var readTimeoutMs: Long = 10_000
    private var writeTimeoutMs: Long = 10_000


    private val okHttpClientBuilder = OkHttpClient.Builder()
    private var client:OkHttpClient?= null
    private val converterFactoryList = arrayListOf<Converter.Factory>()
    private val callAdapterFactoryList = arrayListOf<CallAdapter.Factory>()

    companion object {
        val instance = RetrofitHolder.INSTANCE
    }

    private object RetrofitHolder {
        val INSTANCE = RetrofitBuilder()
    }


    fun baseUrl(baseUrl: String): RetrofitBuilder {
        this.baseUrl = baseUrl
        return this
    }


    /**
     *可选: 默认自动处理cookies (如果设置为false禁用cookies管理器，记得自己处理)
     */
    fun handleCookie(handleCookie: Boolean): RetrofitBuilder {
        this.handleCookie = handleCookie
        return this
    }

    /**
     * 可选: 如果有额外的请求参数要添加
     */
    fun addParam(key: String, value: String): RetrofitBuilder {
        extraParamMap[key] = value
        return this
    }

    fun addParams(params: Map<String, String>): RetrofitBuilder {
        for (key in params.keys) {
            val value = params[key]
            if (value != null && value != "") {
                extraParamMap[key] = value
            }
        }
        return this
    }

    /**
     * 可选: 如果有额外的header要添加
     */
    fun addHeader(key: String, value: String): RetrofitBuilder {
        extraHeaderMap[key] = value
        return this
    }

    fun addHeaders(headers: Map<String, String>): RetrofitBuilder {
        for (key in headers.keys) {
            val value = headers[key]
            if (value != null && value != "") {
                extraHeaderMap[key] = value
            }
        }
        return this
    }

    /**
     * 可选: 如果有额外的拦截器要添加
     */
    fun addInterceptor(interceptor: Interceptor): RetrofitBuilder {
        extraInterceptorList.add(interceptor)
        return this
    }

    fun addInterceptors(interceptorList: List<Interceptor>): RetrofitBuilder {
        extraInterceptorList.addAll(interceptorList)
        return this
    }

    /**
     * 可选: 如果要自定义connect超时时间（默认10秒）
     */
    fun connectTimeout(ms: Long): RetrofitBuilder {
        connectTimeoutMs = ms
        return this
    }

    /**
     *  可选: 如果要自定义read超时时间（默认10秒）
     */
    fun readTimeout(ms: Long): RetrofitBuilder {
        readTimeoutMs = ms
        return this
    }

    /**
     * 可选: 如果要自定义write超时时间（默认10秒）
     */
    fun writeTimeout(ms: Long): RetrofitBuilder {
        writeTimeoutMs = ms
        return this
    }

    /**
     *  调用此处 来修改OKHTTP
     *  可选: 如果想修改okhttp builder  提供在外部做修改
     *  将函数作为参数传递  获取当前okhttpClient.Builder 参数为labmda表达式  返回对象本身
     */
    fun okHttpClientBuilderOption(option: (OkHttpClient.Builder) -> Unit): RetrofitBuilder {
        option(okHttpClientBuilder)
        return this
    }

    /**
     * 可选: 如果有数据解析器Converter要添加，比如GsonConverter
     */
    fun addConverterFactory(factory: Converter.Factory): RetrofitBuilder {
        converterFactoryList.add(factory)
        return this
    }

    /**
     * 可选: 如果有网络请求适配器CallAdapter要添加 ，比如:
     * RxJava3CallAdapterFactory.create() @rxjava
     * CoroutineCallAdapterFactory @协程
     * LiveDataCallAdapterFactory  @livedata
     */
    fun addCallAdapterFactory(factory: CallAdapter.Factory): RetrofitBuilder {
        callAdapterFactoryList.add(factory)
        return this
    }

    /**
     * 可选： 如果想设置缓存上限（设为-1即关闭缓存）  1024_000
     * 此缓存应用于存储的最大字节数
     */
    fun setMaxCacheSize(size: Long): RetrofitBuilder {
        maxCacheSize = size
        return this
    }

    fun build(context: Context): Retrofit {
        // 检测baseUrl 不为空 末尾须是/  实际没有path的 末尾可以不加/
        if (TextUtils.isEmpty(baseUrl)) {
            throw Exception("base url can not be empty")
        } else if (!baseUrl.endsWith("/")) {
            throw Exception("base url must end with /")
        }
        // 默认Interceptor
        val defaultInterceptor = DefaultInterceptor(
            extraParamMap,
            extraHeaderMap
        )
        extraInterceptorList.add(0, defaultInterceptor)
 // 构造OkHttpClient
        val okHttpClient = okHttpClientBuilder.apply {
            // 缓存
            if (maxCacheSize > 0) {
                val cacheDir = File(context.cacheDir, "OkHttpCache")
                cacheDir.mkdirs()
                val cache = Cache(cacheDir, maxCacheSize)
                cache(cache)
            }
            // 超时
            connectTimeout(connectTimeoutMs, TimeUnit.MILLISECONDS)
            readTimeout(readTimeoutMs, TimeUnit.MILLISECONDS)
            writeTimeout(writeTimeoutMs, TimeUnit.MILLISECONDS)
            //出现错误重新连接
            retryOnConnectionFailure(true)
            // Cookie管理
            if (handleCookie) {
                /**
                 * 如需修改 替换CookieJarImpl即可
                 */
                cookieJar(CookieJarImpl(context))
            }
            // 拦截器
            for (interceptor in extraInterceptorList) {
                addInterceptor(interceptor)
            }
        }.build()
        client=okHttpClient
// 构造Retrofit
        val builder = Retrofit.Builder()
        builder.baseUrl(baseUrl)
        builder.client(okHttpClient)
        for (factory in converterFactoryList) {
            builder.addConverterFactory(factory)
        }
        for (factory in callAdapterFactoryList) {
            builder.addCallAdapterFactory(factory)
        }
        return builder.build()
    }

    /**
     * 取消所有的网络请求
     */
    fun cancelAllRequest() {
        client?.dispatcher()?.cancelAll()
    }


}